package com.sh.rpc.spi;

import cn.hutool.core.io.resource.ResourceUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * DIY_spi 加载器
 */
@Slf4j
public class SpiLoader {


    /**
     * 存储已经加载的类   key:类接口名                      value: 类接口名 -> 实现类
     * com.sh.serializer.Serializer                json      xx@15625
     */
    private static Map<String, Map<String, Class<?>>> loaderMap = new ConcurrentHashMap<>();

    /**
     * 对象实例缓存
     * key:类路径  value:实例
     */
    private static Map<String, Object> instanceCache = new ConcurrentHashMap<>();

    /**
     * 系统spi目录
     */
    private static final String RPC_SYSTEM_SPI_DIR = "META-INF/rpc/system/";

    /**
     * 自定义的spi目录
     */
    private static final String RPC_CUSTOM_SPI_DIR = "META-INF/rpc/custom/";

    /**
     * 扫描路径
     */
    private static final String[] SCAN_DIRS = new String[]{RPC_SYSTEM_SPI_DIR, RPC_CUSTOM_SPI_DIR};


    /**
     * 动态加载的类列表，被加载的类列表
     * aslist: 内容可以改变，大小不能改变
     */
    private static final List<Class<?>> LOAD_CLASS_LIST = Arrays.asList(SpiLoader.class);


    /**
     * 加载所有类
     */
//    public static void loadAll() {
//        log.info("开始加载spi");
//        for (Class<?> aClass : LOAD_CLASS_LIST) {
//            load(aClass);
//        }
//    }

    /**
     *  根据 class  和 String 获取实例对象
     */
    public static <T> T getInstance(Class<T> tClass, String key){

        String tClassName = tClass.getName();// com.sh.serializer.Serializer
        Map<String, Class<?>> keyClassMap = loaderMap.get(tClassName);   // Serializer接口的实现类
        // jdk   :   class com.sh.rpc.serializer.JdkSerializer"
        if(keyClassMap==null){
            log.error("SpiLoader 没有加载 {} 类型", tClassName);
            throw new RuntimeException(String.format("SpiLoader 没有加载 %s 类型", tClassName));
        }
        if (!keyClassMap.containsKey(key)) {
            log.error("{} SpiLoader 找不到 {} 的配置信息", tClassName, key);
            throw new RuntimeException(String.format("%s 找不到 %s 的配置信息", tClassName, key));
        }
        Class<?> implClass = keyClassMap.get(key);    // class  com.sh.serializer.JsonSerializer
        String implClassName = implClass.getName();   // com.sh.serializer.JsonSerializer
        if (!instanceCache.containsKey(implClassName)){
            try{
                //         com.sh.rpc.serializer.JsonSerializer  :   xxxx@15625
                instanceCache.put(implClassName, implClass.newInstance());
            }catch (InstantiationException | IllegalAccessException e){
                log.error("创建实例失败", e);
                throw new RuntimeException(e);
            }
        }
        return (T) instanceCache.get(implClassName);
    }



    /**
     * 加载指定类
     */
    public static Map<String, Class<?>> load(Class<?> loadClass) {
        log.info("加载类型为 {} 的spi", loadClass.getName());
        Map<String, Class<?>> keyClassMap = new HashMap<>();   // json  json实例
        for (String scanDir : SCAN_DIRS) {
            List<URL> resources = ResourceUtil.getResources(scanDir + loadClass.getName());
            for (URL resource : resources) {
                try {
                    InputStreamReader inputStreamReader = new InputStreamReader(resource.openStream());
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        String[] strArray = line.split("=");
                        if (strArray.length > 0) {
                            String key = strArray[0];   // json
                            String className = strArray[1];  // com.sh.serializer.JsonSerializer
                            keyClassMap.put(key, Class.forName(className));   // json  :   class com.sh.rpc.serializer.JsonSerializer
                        }
                    }
                } catch (Exception e) {
                    log.error("加载spi失败", e);
                }
            }
        }
        // 将加载的类放入缓存中     com.sh.serializer.Serializer      json -> xx@15625
        loaderMap.put(loadClass.getName(), keyClassMap);
        return keyClassMap;
    }
    /*
       System.out.println(Person.class);   // class com.yc.Person
        System.out.println(Person.class.getName());  // com.yc.Person
        System.out.println(Person.class.getSimpleName());  // Person
        System.out.println(person.getClass());  // class com.yc.Person   person是小写嘎
     */

}
